//
//  SnifferApp.m
//  PacketSniffer
//
//  Created by nark on 16/04/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "SnifferApp.h"
#import "IconTextFieldCell.h"
#import "header.h"

@implementation SnifferApp


#pragma mark -
#pragma mark SnifferApp methods
- (void)awakeFromNib {
	
	root			= [[PSNode alloc] init];
	propertyDict	= [[NSMutableDictionary alloc] init];
	devices			= [[NSMutableArray alloc] init];
	
	// Use DeviceFinder to get computer devices
	devFinder = [[PSDeviceFinder alloc] init];
	devices   = [devFinder lookupForAllDevices];
	
	// add Devices to devices PopUpButton
	for(PSDevice *d in devices) {
		[devicesPopUp addItemWithTitle:[d name]];
	}
	
	// register default notification center
	nc = [NSNotificationCenter defaultCenter];
	
	// observe coming ethernet packet
	[nc addObserver:self 
		   selector:@selector(receiveEthernetPacket:) 
			   name:PSReceiveEthernetPacketNotification 
			 object:nil];
	
	NSTableColumn* tableColumn = [[detailsOutlineView tableColumns] objectAtIndex:0];
    IconTextFieldCell* imageAndTextCell = [[IconTextFieldCell alloc] init];
    [tableColumn setDataCell:imageAndTextCell];
}



/**
 * This IBAction start packet capture
 *
 */
- (IBAction)startCapture:(id)sender {
	
	ps = [[PSPacketSniffer alloc] initWithDevice:[devices objectAtIndex:[devicesPopUp indexOfSelectedItem]]
									 captureType:PSEveryCaptureType
								 promiscuousMode:YES
									 withTimeout:0
										/*delegate:self*/];
	

	if([[filterTextField stringValue] length] > 0) {
		PSFilter *filter = [[PSFilter alloc] initWithFilter:[filterTextField stringValue]];
		
		if(filter != nil) {
			[ps setFilter:filter];
		}
	}
	
	if(ps) {
		[ps startCapture];
		[snifferIndicator startAnimation:self];
	}
}


/**
 * This IBAction stop packet capture
 *
 */
- (IBAction)stopCapture:(id)sender {
	if(ps) {
		[ps stopCapture];
		[snifferIndicator stopAnimation:self];
	}
}

- (IBAction)clear:(id)sender {
	[[root children] removeAllObjects];
	[detailsOutlineView reloadData];
	
	[propertyDict removeAllObjects];
	[propertyTableView reloadData];
}


-(BOOL)shouldCloseSheet:(id)sender {
	[self startCapture:sender];
	return YES;
}


- (void)receiveEthernetPacket:(NSNotification *)_notification {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	PSEthernetPacket *ethPacket = [[_notification userInfo] valueForKey:@"packet"];
	
	if(ethPacket) {
		@synchronized(root) {
			[[root children] addObject:ethPacket];
		}

		[detailsOutlineView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
		[detailsOutlineView scrollRowToVisible:[detailsOutlineView numberOfRows]-1];
	}
	[pool release];
}


- (void)updatePropertyView:(PSNode *)_node {
	[propertyDict removeAllObjects];
	
	if([_node isKindOfClass:[PSEthernetPacket class]]) {
		PSEthernetPacket *ethPacket = (PSEthernetPacket *)_node;
		propertyDict = [ethPacket properties];
		
	} else if([_node isKindOfClass:[PSIPPacket class]]) {
		PSIPPacket *ipPacket = (PSIPPacket *)_node;
		propertyDict = [ipPacket properties];
		
	} else if([_node isKindOfClass:[PSTCPHeader class]]) {
		PSTCPHeader *tcpHeader = (PSTCPHeader *)_node;
		propertyDict = [tcpHeader properties];
		
	} else if([_node isKindOfClass:[PSUDPHeader class]]) {
		PSUDPHeader *udpHeader = (PSUDPHeader *)_node;
		propertyDict = [udpHeader properties];
		
	}
	[propertyTableView reloadData];
}



#pragma mark -
#pragma mark NSTableView (ipPackets) Delegate & DataSource methods

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
	return [propertyDict count];
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
	id value = nil;
	
	if([[aTableColumn identifier] isEqualToString:@"key"]) {
		value = [[propertyDict allKeys] objectAtIndex:rowIndex];
	}
	if([[aTableColumn identifier] isEqualToString:@"value"]) {
		value = [[propertyDict allValues] objectAtIndex:rowIndex];
	}
	
	return value;
}


#pragma mark -
#pragma mark NSOutlineView DataSource

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
    return (item == nil) ? [[root children] count] : [[item children] count];
} 

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
    return (item == nil) ? ([[root children] count] != 0) : ([[item children] count] != 0);
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
    return (item == nil) ? [[root children] objectAtIndex:index] : [[item children] objectAtIndex:index];
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
	id value = nil;
	
	if([[tableColumn identifier] isEqual:@"name"]) {
		if([item isKindOfClass:[PSEthernetPacket class]])
			value = @"Ethernet Packet";
		
		else if([item isKindOfClass:[PSIPPacket class]])
			value = @"IP Packet";
		
		else if([item isKindOfClass:[PSARPPacket class]])
			value = @"ARP Packet";
		
		else if([item isKindOfClass:[PSUDPHeader class]])
			value = @"UDP Header";
		
		else if([item isKindOfClass:[PSTCPHeader class]])
			value = @"TCP Header";
		
		else if([item isKindOfClass:[PSICMPHeader class]])
			value = @"ICMP Header";
		
	} else if ([[tableColumn identifier] isEqual:@"source"]) {
		if([item isKindOfClass:[PSEthernetPacket class]])
			value = [(PSEthernetPacket *)item sourceMACAddress];
		
		else if([item isKindOfClass:[PSIPPacket class]])
			value = [(PSIPPacket *)item sourceIP];
		
		else if([item isKindOfClass:[PSARPPacket class]])
			value = @"";
		
		else if([item isKindOfClass:[PSUDPHeader class]])
			value = [NSString stringWithFormat:@"%d", [(PSUDPHeader *)item sourcePort]];
		
		else if([item isKindOfClass:[PSTCPHeader class]])
			value = value = [(PSTCPHeader *)item sourcePort];
		
		else if([item isKindOfClass:[PSICMPHeader class]])
			value = @"";
		
	} else if ([[tableColumn identifier] isEqual:@"destination"]) {
		if([item isKindOfClass:[PSEthernetPacket class]])
			value = [(PSEthernetPacket *)item destinationMACAddress];
		
		else if([item isKindOfClass:[PSIPPacket class]])
			value = [(PSIPPacket *)item destinationIP];
		
		else if([item isKindOfClass:[PSARPPacket class]])
			value = @"";
		
		else if([item isKindOfClass:[PSUDPHeader class]])
			value = [NSString stringWithFormat:@"%d", [(PSUDPHeader *)item destinationPort]];
		
		else if([item isKindOfClass:[PSTCPHeader class]])
			value = [(PSTCPHeader *)item destinationPort];
		
		else if([item isKindOfClass:[PSICMPHeader class]])
			value = @"";
	}
	
	return value;
}


#pragma mark -
#pragma mark NSOutlineView Delegate


- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item {
	if([item isKindOfClass:[PSNode class]]) {
		[self updatePropertyView:(PSNode *)item];
	}
	return YES;
}

- (void)outlineView:(NSOutlineView*)outlineView willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn*)tableColumn item:(id)item {    
   
	if ([[tableColumn identifier] isEqualToString: @"name"] && [cell respondsToSelector:@selector(setTextFieldIcon:)]) {
		
		if([item isKindOfClass:[PSEthernetPacket class]]) {
			[(IconTextFieldCell*)cell setTextFieldIcon:[NSImage imageNamed:@"Ethernet"]];
			
		} else if([item isKindOfClass:[PSIPPacket class]]) {
			[(IconTextFieldCell*)cell setTextFieldIcon:[NSImage imageNamed:@"IP"]];
			
		} else if([item isKindOfClass:[PSPacket class]]) {
			[(IconTextFieldCell*)cell setTextFieldIcon:[NSImage imageNamed:@"Packet"]];
			
		} else {
			[(IconTextFieldCell*)cell setTextFieldIcon:[NSImage imageNamed:@"Packet"]];
		}
	}
}

@end
